package com.neborosoft.FlyingDog.android.playing.modes;

import android.app.Activity;
import android.os.Parcelable;
import android.view.View;
import android.widget.AbsListView;
import com.neborosoft.FlyingDog.android.MyActivity;
import com.neborosoft.FlyingDog.android.gui.adapters.listview.SongsPlayListAdapter;
import com.neborosoft.FlyingDog.logic.database.content.identified.Identified;
import com.neborosoft.FlyingDog.logic.search.suggestions.SuggestionsProvider;
import com.neborosoft.android.events.HistoryManager;
import com.neborosoft.android.gui.adapters.listview.OnItemClick;
import com.neborosoft.android.gui.adapters.listview.ViewArrayAdapter;
import com.neborosoft.android.gui.wrappers.ListViewSwitcher;
import com.neborosoft.android.threading.AndroidOnHostThreadExecutor;
import com.neborosoft.lib.collections.list.NavigationList;
import com.neborosoft.lib.collections.tree.AsyncNTreeWrapper;
import com.neborosoft.lib.collections.tree.NTree;
import com.neborosoft.lib.handlers.OnHardwareBackPressed;
import com.neborosoft.lib.threading.OnHostThreadExecutor;
import com.neborosoft.lib.threading.Threading;
import com.neborosoft.lib.utilities.Utilities;
import com.neborosoft.lib.utilities.algorithms.Search;

import java.util.List;
import java.util.concurrent.Executor;

/**
 * Created with IntelliJ IDEA.
 * User: CM
 * Date: 01.12.12
 * Time: 18:34
 * To change this template use File | Settings | File Templates.
 */
public abstract class TreeStructuredPlayingMode extends PlayingModeWithSuggestions{
    private static final Executor EXECUTOR = Threading.getSharedExecutor();
    private static final OnHostThreadExecutor ON_HOST_THREAD_EXECUTOR = new AndroidOnHostThreadExecutor();

    private static final HistoryManager HISTORY_MANAGER = HistoryManager.getInstance();
    private AsyncNTreeWrapper tree;
    private ViewArrayAdapter[] adaptersPerLevel;
    private List rootAdapterElementsBeforeSearching;

    private static class State{
        NTree.State treeState;
        Parcelable listViewState;
    }

    private class AsyncNTreeImplementation extends AsyncNTreeWrapper{
        private AsyncNTreeImplementation(NTree tree) {
            super(tree, EXECUTOR, ON_HOST_THREAD_EXECUTOR);
        }

        @Override
        protected void onElementsUpdated(int level, List elements) {
            updateCurrentAdapterElements();
        }

        @Override
        protected boolean shouldEnterChildAsync(Object parent, int level) {
            return TreeStructuredPlayingMode.this.shouldEnterChildAsync(parent, level);
        }
    }

    protected boolean shouldEnterChildAsync(Object parent, int level){
        if(parent instanceof Identified){
            return !((Identified)parent).isLocal();
        } else {
            return true;
        }
    }

    @Override
    protected SongsPlayListAdapter getSongsPlayListAdapter(){
        return (SongsPlayListAdapter)adaptersPerLevel[tree.getLevelsCount() - 1];
    }

    protected ViewArrayAdapter getCurrentLevelAdapter(){
        int currentLevel = tree.getLevel();
        return adaptersPerLevel[currentLevel];
    }

    protected AsyncNTreeWrapper getTree() {
        return tree;
    }

    public void updateCurrentAdapterElements(){
        List elements = tree.getElements();
        if(rootAdapterElementsBeforeSearching != null && getCurrentLevel() == 0){
            elements = rootAdapterElementsBeforeSearching;
            tree.restart(elements);
            rootAdapterElementsBeforeSearching = null;
        }

        ViewArrayAdapter adapter = getCurrentLevelAdapter();
        ListViewSwitcher listViewSwitcher = getListViewSwitcher();
        int level = tree.getLevel();

        SongsPlayListAdapter selectedSongsPlayListAdapter = SongsPlayListAdapter.getSelectedSongsAdapter();
        boolean selectedSongsPlayListAdapterContent =
                SongsPlayListAdapter.selectedSongsAdapterHasSpecifiedContent(elements);

        if(adapter == selectedSongsPlayListAdapter && !selectedSongsPlayListAdapterContent){
            adapter = new SongsPlayListAdapter(getActivity().getApplicationContext(),
                    listViewSwitcher.getListView());
        } else if(selectedSongsPlayListAdapterContent) {
            adapter = selectedSongsPlayListAdapter;
        }

        adaptersPerLevel[level] = adapter;
        listViewSwitcher.setAdapter(adapter);
        adapter.setElements(elements);

        NavigationList.resumePageLoadingOfNavigationList(elements);

        if(elements instanceof NavigationList){
            NavigationList navigationList = (NavigationList)elements;
            final ViewArrayAdapter finalAdapter = adapter;
            navigationList.setOnNextPageLoadingFinished(new NavigationList.OnNextPageLoadingFinished() {
                @Override
                public void onLoadingFinished() {
                    finalAdapter.notifyDataSetChanged();
                }
            });
        }
    }

    protected void updateAdapterAndListViewValue(){
        ViewArrayAdapter adapter = getCurrentLevelAdapter();
        int listViewId = getCurrentLevelListViewResourceId();

        ListViewSwitcher listViewSwitcher = getListViewSwitcher();
        listViewSwitcher.switchTo(listViewId, adapter);
    }

    protected void enterChild(Object element, int position){
        NavigationList.pausePageLoadingOfNavigationList(tree.getElements());
        tree.enterChild(position);
        updateAdapterAndListViewValue();
        updateCurrentAdapterElements();
    }

    protected void onChildExit(){

    }

    protected void onTreeItemClick(Object element, int position, int level){
        final Parcelable listViewState = getListViewState();
        enterChild(element, position);

        HISTORY_MANAGER.pushHardwareBackPressedListener(new OnHardwareBackPressed() {
            @Override
            public void onBack() {
                tree.exitChild();
                updateAdapterAndListViewValue();
                updateCurrentAdapterElements();
                onChildExit();
                AbsListView listView = getListView();
                listView.onRestoreInstanceState(listViewState);
            }
        });
    }

    private class OnTreeItemClick implements OnItemClick{
        @Override
        public void onClick(final Object key, View view, int position) {
            int level = tree.getLevel();
            onTreeItemClick(key, position, level);
        }
    }

    private void initAdapterAndListViewValueForLevel(int level){
        OnItemClick onListItemClick = new OnTreeItemClick();

        Class<? extends ViewArrayAdapter> adapterClass;
        if(level != tree.getLevelsCount() - 1){
            adapterClass = getListViewAdapterClass(level);
        } else {
            adapterClass = SongsPlayListAdapter.class;
        }

        int levelListViewResourceId = getListViewResourceIdForLevel(level);
        AbsListView listView = (AbsListView)getActivity().findViewById(levelListViewResourceId);

        ViewArrayAdapter adapter;
        try {
             adapter = Utilities.createObjectOfClass(adapterClass, getActivity(), listView);
        }
        catch (Throwable e){
            Utilities.logException(e);
            return;
        }

        adaptersPerLevel[level] = adapter;

        if(level != tree.getLevelsCount() - 1){
            adapter.setOnItemClickListener(onListItemClick);
        }
    }

    public TreeStructuredPlayingMode(Activity activity, ListViewSwitcher listViewSwitcher, NTree tree) {
        super(activity, listViewSwitcher);
        this.tree = new AsyncNTreeImplementation(tree);

        adaptersPerLevel = new ViewArrayAdapter[tree.getLevelsCount()];

        for(int level = 0; level < adaptersPerLevel.length; level++){
            initAdapterAndListViewValueForLevel(level);
        }
    }

    @Override
    public void showInListView(boolean restoreState) {
        if (!restoreState) {
            tree.restart();
        }
        updateAdapterAndListViewValue();
        updateCurrentAdapterElements();
    }

    private int getCurrentLevelListViewResourceId(){
        int level = tree.getLevel();
        return getListViewResourceIdForLevel(level);
    }

    protected ViewArrayAdapter getAdapterForLevel(int level){
        return adaptersPerLevel[level];
    }

    protected int getCurrentLevel(){
        return tree.getLevel();
    }

    protected void setNavigationListNotifiers(NavigationList navigationList) {
        navigationList.setOnNextPageLoadingFinished(new NavigationList.OnNextPageLoadingFinished() {
            @Override
            public void onLoadingFinished() {
                ViewArrayAdapter adapter = getCurrentLevelAdapter();
                adapter.notifyDataSetChanged();
            }
        });
    }

    @Override
    public void onSearchFinished(final Object searchResult) {
        tree.restart((List)searchResult);
        final AbsListView listView = getListViewSwitcher().getListView();
        listView.setSelection(0);

        listView.post(new Runnable() {
            @Override
            public void run() {
                updateAdapterAndListViewValue();
                updateCurrentAdapterElements();
            }
        });
    }

    @Override
    public List<String> getSearchSuggestions(String query) {
        if(getSuggestionsProvider() != null){
            return super.getSearchSuggestions(query);
        }

        if(getCurrentLevel() != 0){
            showInListView(false);
        }

        final ViewArrayAdapter adapter = getCurrentLevelAdapter();
        List elements = adapter.getElements();
        if(rootAdapterElementsBeforeSearching == null){
            rootAdapterElementsBeforeSearching = elements;
        }

        final List filteredElements = Search.filter(rootAdapterElementsBeforeSearching, query);

        getListViewSwitcher().getListView().post(new Runnable() {
            @Override
            public void run() {
                adapter.setElements(filteredElements);
                tree.restart(filteredElements);
            }
        });

        return null;
    }

    @Override
    protected Object performSearch(String query) {
        HISTORY_MANAGER.pushHardwareBackPressedListener(new OnHardwareBackPressed() {
            @Override
            public void onBack() {
                onSkipSearch();
            }
        });

        return null;
    }

    @Override
    public void onSkipSearch() {
        if(rootAdapterElementsBeforeSearching != null && getCurrentLevel() == 0){
            ViewArrayAdapter adapter = getCurrentLevelAdapter();
            adapter.setElements(rootAdapterElementsBeforeSearching);
            rootAdapterElementsBeforeSearching = null;
        }
    }

    @Override
    protected SuggestionsProvider createSuggestionsProvider() {
        return null;
    }

    @Override
    public Object getState() {
        State state = new State();
        state.listViewState = getListViewState();
        state.treeState = tree.getState();
        NavigationList.pausePageLoadingOfNavigationList(tree.getElements());
        return state;
    }

    @Override
    public void restoreState(Object stateObject) {
        State state = (State)stateObject;
        tree.restoreState(state.treeState);
        updateAdapterAndListViewValue();
        updateCurrentAdapterElements();
        getListView().onRestoreInstanceState(state.listViewState);
    }

    @Override
    public void onAnotherModeSelected() {
        NavigationList.pausePageLoadingOfNavigationList(tree.getElements());
    }

    protected abstract int getListViewResourceIdForLevel(int level);
    protected abstract Class<? extends ViewArrayAdapter> getListViewAdapterClass(int level);
}
